//////////////////////////////////////////////
// main.cpp
//
//////////////////////////////////////////////

/// Defines / Macros -------------------------

#define SHOWCASE_ICON 1
#define SHOWCASE_TEXTURE 1
#define SHOWCASE_NO_BLUE 1

/// Includes ---------------------------------

#if SHOWCASE_TEXTURE == 1
	// nkGraphics
	#include <NilkinsGraphics/Buffers/MapRequestDescriptor.h>
	#include <NilkinsGraphics/Buffers/MapResult.h>
	#include <NilkinsGraphics/Buffers/UnmapRequestDescriptor.h>

	#include <NilkinsGraphics/Textures/Texture.h>
	#include <NilkinsGraphics/Textures/TextureManager.h>

	#include <NilkinsGraphics/System.h>
#endif

// nkImages
#include <NilkinsImages/Data/AlignmentDescriptor.h>
#include <NilkinsImages/Data/Image.h>

#include <NilkinsImages/Dds/DdsEncoder.h>

// nkMaths
#include <NilkinsMaths/Algebra/Vector.h>

// nkMemory
#include <NilkinsMemory/Containers/Buffer.h>

// nkResources
#include <NilkinsResources/ResourceManager.h>

#if SHOWCASE_ICON == 1
	// nkWinUi
	#include <NilkinsWinUi/Components/ComponentManager.h>
	#include <NilkinsWinUi/Components/Window.h>

	#include <NilkinsWinUi/Inputs/InputSystem.h>

	#include <NilkinsWinUi/System.h>
#endif

// Standards
#include <fstream>
#include <iostream>

/// Function ---------------------------------

int main ()
{
	nkMemory::Buffer imgData = nkResources::ResourceManager::getInstance()->loadFileIntoMemory("Data/cloudMap.dds") ;

	#if SHOWCASE_TEXTURE == 1
		// A texture requires some alignment constraints
		nkImages::AlignmentDescriptor alignmentDesc ;
		alignmentDesc._alphaMode = nkImages::ALPHA_MODE::ALPHA ;

		nkImages::Image img = nkImages::DdsEncoder::decode(imgData, alignmentDesc) ;
	#else
		if (!nkImages::DdsEncoder::canDecode(imgData))
			return 0 ;

		nkImages::Image img = nkImages::DdsEncoder::decode(imgData) ;
	#endif

	std::cout << "Dimensions : " << img.getWidth() << "x" << img.getHeight() << std::endl ;

	nkMaths::Vector pixel = img.getPixel(16, 16) ;

	std::cout << "Pixel at (16, 16) : " << pixel._x << ", " << pixel._y << ", " << pixel._y << std::endl ;

	#if SHOWCASE_TEXTURE == 1
		// Init nkGraphics
		nkGraphics::System* graphicsSystem = nkGraphics::System::getInstance() ;

		if (!graphicsSystem->initialize())
			return -1 ;

		// Prepare a texture
		nkGraphics::Texture* tex = nkGraphics::TextureManager::getInstance()->createOrRetrieve("texture") ;

		tex->setFromImage(img) ;
		tex->load() ;

		// Check what's inside
		nkGraphics::MapRequestDescriptor request ;
		request._mapType = nkGraphics::MAP_READ ;
		nkGraphics::MapResult mapResult = tex->map(request) ;

		unsigned int mapOffset = mapResult._rowPitch * 16 + img.getPixelByteSize() * 16 ;
		nkMaths::Vector pixelMap (mapResult._data[mapOffset], mapResult._data[mapOffset + 1], mapResult._data[mapOffset + 2]) ;
		
		std::cout << "Texture pixel at (16, 16) : " << pixelMap._x << ", " << pixelMap._y << ", " << pixelMap._z << std::endl ;

		tex->unmap(nkGraphics::UnmapRequestDescriptor()) ;

		// Clean up
		graphicsSystem->kill() ;
	#endif

	#if SHOWCASE_ICON == 1
		// Init nkWinUi
		nkWinUi::System* uiSystem = nkWinUi::System::getInstance() ;

		if (!uiSystem->initialize())
			return -1 ;

		// Make a window
		nkWinUi::Window* window = (nkWinUi::Window*)nkWinUi::ComponentManager::getInstance()->createOrRetrieve("mainWindow", nkWinUi::COMPONENT_TYPE::WINDOW) ;
		window->setWidth(800) ;
		window->setHeight(600) ;

		window->setIcon(img) ;

		window->load() ;

		// Prepare closing callback
		bool windowOpened = true ;

		nkWinUi::InputSystem::getInstance()->setCloseCallback
		(
			[&windowOpened] (nkWinUi::Component* caller) -> bool
			{
				windowOpened = false ;

				// We handled the event, but return false to mean that the component itself should do its logic
				return false ;
			}
		) ;

		// Tick system waiting for it to close
		while (windowOpened)
			uiSystem->tick() ;

		// Clean up
		uiSystem->prepareForShutdown() ;
		uiSystem->kill() ;
	#endif

	#if SHOWCASE_NO_BLUE == 1
		// Prepare to work on the image
		unsigned char* dataPtr = img.getDataPtr() ;

		unsigned int width = img.getWidth() ;
		unsigned int height = img.getHeight() ;
		unsigned int lineStride = img.getRowByteSize() ;
		unsigned int pixelStride = img.getPixelByteSize() ;

		for (unsigned int y = 0 ; y < height ; ++y)
		{
			unsigned int lineOffset = y * lineStride ;

			for (unsigned int x = 0 ; x < width ; ++x)
			{
				unsigned int pixelOffset = lineOffset + x * pixelStride ;

				dataPtr[pixelOffset] = 0 ;
			}
		}

		// Reencode the data and output it to disk
		nkMemory::Buffer imgAlteredData = nkImages::DdsEncoder::encode(img) ;

		std::ofstream outFile ("output.dds", std::ofstream::binary) ;
		outFile.write((char*)imgAlteredData.getData(), imgAlteredData.getSize()) ;
		outFile.close() ;
	#endif

	// Done
	system("pause") ;
	return 0 ;
}